package org.poem.service.impl;

import org.poem.UkeyException;
import org.poem.common.UkeyComon;
import org.poem.service.UkeyService;
import org.poem.vo.UkeyReadString;
import org.poem.vo.UkeyWriteData;

/**
 * @author ：org.poem.service.impl
 * @author ：Administrator
 * @date ：Created in 2021-10-11 11:05
 * @description：ukey的相应操作服务
 * @modified By：
 * @version: $
 */
public class UkeyServiceImpl implements UkeyService {
    private static final com.softkey.jsyunew3 j9;

    static {
        j9 = new com.softkey.jsyunew3();
    }

    /**
     * 设置 ukey的唯一id
     *
     * 1、设置锁的ID,设置之前建议设置好锁的增强算法二
     * 2、对于同一增强算法密钥二，不同的ID种子，生成的ID不相同
     * 3、对于同一ID种了，不同的增强算法密钥二，生成的ID也不相同
     * 4、根据已知ID，无法推算出ID种子及增强算法密钥二
     * 5、即你生成的ID，只要ID种子及增强算法密钥二不让别人知道，别人就没有办法生成同一ID
     * @param seed 因子
     * @return
     */

    private void setUkeyUniqueIdBySeed(String seed) throws UkeyException {
        int verex = 0;
        String devicePath = j9.FindPort(0);
        if (j9.get_LastError() != 0) {
            throw new UkeyException("未找到加密锁,请插入加密锁后，再进行操作。");
        }
        verex = j9.GetVersionEx(devicePath);
        if (j9.get_LastError() != 0) {
            throw new UkeyException("返回加密锁扩展版本号错误。");
        }
        if (verex < 32) {
            throw new UkeyException("锁的扩展版本少于32,不支持普通算法二。");
        } else {
            if (j9.SetID(seed, devicePath) == 0) {
                System.out.println("设置ID成功。");
            } else {
                throw new UkeyException("设置ID错误");
            }
        }
    }

    /**
     * 读取ukey的ukey
     *
     * @return
     * @throws UkeyException
     */
    private String getUkeyUniqueId() throws UkeyException {
        String devicePath = j9.FindPort(0);
        if (j9.get_LastError() != 0) {
            throw new UkeyException("未找到加密锁,请插入加密锁后，再进行操作。");
        }
       /*'用于返回加密狗的ID号，加密狗的ID号由两个长整型组成。
            '提示1：锁ID可以由开发商自行设置*/
        int ID1, ID2;
        ID1 = (int) j9.GetID_1(devicePath);
        if (j9.get_LastError() != 0) {
            throw new UkeyException("返回ID1错误");
        }
        ID2 = (int) j9.GetID_2(devicePath);
        if (j9.get_LastError() != 0) {
            throw new UkeyException("返回ID1错误");
        }
        return Integer.toHexString(ID1) + Integer.toHexString(ID2);
    }

    /**
     * 写入
     *
     * @param ukeyWriteData 数据
     */
    @Override
    public void writeStringToUkey(UkeyWriteData ukeyWriteData) throws UkeyException {
        String data = ukeyWriteData.getData();
        String devicePath = j9.FindPort(0);
        if (j9.get_LastError() != 0) {
            throw new UkeyException("未找到加密锁,请插入加密锁后，再进行操作。");
        }
        setUkeyUniqueIdBySeed(ukeyWriteData.getId());
        //注意，如果是普通单片机芯片，储存器的写次数是有限制的，写次数为1000次，读不限制，如果是智能芯片，写的次数为10万次
        // 这个例子与上面的不同之处是，可以写入非固定长度的字符串，它是先将字符串的长度写入到首地址，然后再写入相应的字符串
        //写入字符串带长度，,使用默认的读密码
        int ret;
        int nlen;
        byte[] buf = new byte[1];
        //写入字符串到地址1
        nlen = j9.NewWriteString(data, (short) 1, UkeyComon.H_KEY, UkeyComon.L_KEY, devicePath);
        if (j9.get_LastError() != 0) {
            throw new UkeyException("设置ukey出现错误，请稍后重试");
        }
        //写入字符串的长度到地址0
        buf[0] = (byte) nlen;
        j9.SetBuf(0, buf[0]);
        ret = j9.YWriteEx((short) 0, (short) 1, UkeyComon.H_KEY, UkeyComon.L_KEY, devicePath);
        if (ret != 0) {
            throw new UkeyException("设置ukey出现错误，请稍后重试");
        } else {
            System.out.println("写入字符串(带长度)成功");
        }
    }

    /**
     * 读取字符串
     */
    @Override
    public UkeyReadString readUkeyString() throws UkeyException {
        String devicePath = j9.FindPort(0);
        if (j9.get_LastError() != 0) {
            throw new UkeyException("未找到加密锁,请插入加密锁后，再进行操作。");
        }
        //这个例子与上面的不同之处是，可以读取非固定长度的字符串，它是先从首地址读取字符串的长度，然后再读取相应的字符串
        int ret;
        short nlen;
        String outString;
        //先从地址0读到以前写入的字符串的长度
        ret = j9.YReadEx((short) 0, (short) 1, UkeyComon.H_KEY, UkeyComon.L_KEY, devicePath);
        nlen = j9.GetBuf(0);
        if (ret != 0) {
            throw new UkeyException("设置ukey出现错误，请稍后重试");
        }
        //再读取相应长度的字符串
        outString = j9.NewReadString((short) 1, nlen, UkeyComon.H_KEY, UkeyComon.L_KEY, devicePath);
        if (j9.get_LastError() != 0) {
            System.out.println("读取字符串(带长度)错误。错误码：");
        } else {
            System.out.println("已成功读取字符串(带长度)：" + outString);
        }
        String produceDate = j9.GetProduceDate(devicePath);
        if (j9.get_LastError() != 0) {
            throw new UkeyException("返回出厂编码错误");
        }
        UkeyReadString ukeyReadString = new UkeyReadString();
        ukeyReadString.setStr(outString);
        ukeyReadString.setProduceDate(produceDate);
        ukeyReadString.setUkeyUniqueId(getUkeyUniqueId());
        return ukeyReadString;
    }
}
